/*
*  C Implementation: proc_creation
*
* Description: This defines several useful functions for piping jobs.
*   Also, a there are functions to throw the jobs in the background
*
* Author: w00t,,, <w00t@bftp>, (C) 2009
*
* Copyright: See COPYING file that comes with this distribution
*
*/
#define _POSIX_SOURCE
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

#include "helper.h"
#include "wrappers.h"

extern sigset_t maskchld;
/* bg_create throws a SINGLE program into the background*/
/* it is not designed to do things like cat file.c | sort &*/
void bg_create(char *argv[]){ /*pass the command + arguments in this vector.  Do not include &*/
    char job_name[32];
	struct job_t* job;
	int pid=-1;	
    /*redundant block, it is that important!!*/
    Sigprocmask(SIG_BLOCK,&maskchld,NULL);
    
    
    pid=Fork();
                                        
    if(pid==0)  /*child*/
    {
        Setpgid(0,0);   /*make child has own process group so it can share signals*/
            
        Sigprocmask(SIG_UNBLOCK,&maskchld,NULL);    /*this is the child, */
                                                        /* it should have this signal unblocked       */
        Signal(SIGINT,SIG_DFL);     /*default SIGINT handler*/        
        Signal(SIGTSTP,SIG_DFL);    /*default SIGSTP handler*/
        if(execv(argv[0],argv)==-1){                                                
            printf("%s: Command not found\n",argv[0]);
            exit(0);
        }    
       
        return;
    }   /*parent    */
        
    /*give job the name of the program   */     
    strcpy(job_name,argv[0]);
    strcat(job_name,"\n");
    
    addjob(jobs,pid,BG,job_name);
    job=getjobpid(jobs,pid);
    printf("[%d] (%d) ", job->jid, job->pid);
    printf("%s", job->cmdline);
        
        /*since editting our job list has been done, we may start processing child signals*/
    Sigprocmask(SIG_UNBLOCK,&maskchld,NULL); 
}

/*fg_piped_create*/
/*This function "recursively forks", connecting pipes between one fork and the next*/
/*when there are no more next forks (i.e. no more next programs) it completes and waits*/

/*here is an example of what argvv and num_forks may look like
*
* here is what the command looks like: ls -l -r | sort | grep txt
*
* num_forks = 3;
* argvv[0] = argv = {ls, -l, -r, NULL}
* argvv[1] = argv = {sort, NULL}
* argvv[2] = argv = {grep, txt, NULL}
* so argvv[2][1] is "txt"
* so argvv[2][2] is a null pointer
*/ 
extern struct job_t jobs[MAXJOBS];
void fg_piped_create(char **argvv[], int num_forks){
    char job_name[32];
	struct job_t* job;
	int pid=-1; /*worry if this variables stays -1*/
    int i;
    
    int in_pipe[2];
    int out_pipe[2];
	
    /*redundant block, it is that important!!*/
    Sigprocmask(SIG_BLOCK,&maskchld,NULL);
    
    Pipe(in_pipe); 
    /*in each iteration:  */
    for(i=0; i<num_forks; i++){		
        pid = -1;
        
                
        Pipe(out_pipe);        
                
        pid=Fork();
        /*if we are on the last program, make sure the outpipe writes to std_out*/
        if(pid==0){/*child*/
            Setpgid(0,0);   /*make child has own process group so it can share signals*/
            
/*             printf("%d-inpipe-%d",in_pipe[1],in_pipe[0]);*/
/*             printf("  <->    %d-outpipe-%d    iteration - %d\n",out_pipe[1],out_pipe[0],i);*/
/*             set up incoming pipe if not first*/
            if(i!=0){
                close( in_pipe[1] );    /*we don't need it's write end, we have to read!*/
                dup2( in_pipe[0], 0 );        /*replace std_in with the read end*/
                close( in_pipe[0] );          /*we don't need this extra read end*/
            }else{
                close( in_pipe[0] ); 
                close( in_pipe[1] );
            }
            
            /*set up outgoing pipe if not last program*/
            if(i!=num_forks-1){
                close( out_pipe[0] );  /*we don't care about the read end*/       
                dup2( out_pipe[1], 1); /*write end set as std_out*/
                close( out_pipe[1] );  /*we don't need this extra write end*/
            }else{
                close( out_pipe[0] );
                close( out_pipe[1] );
            }
            
            
            Sigprocmask(SIG_UNBLOCK,&maskchld,NULL);    /*this is the child, it should have this signal unblocked */
            Signal(SIGTSTP,SIG_DFL);        /*default SIGINT handler */
            Signal(SIGINT,SIG_DFL);         /*default SIGSTP handler */
            
            if(execv(argvv[i][0],argvv[i])==-1){
                printf("%s: Command not found %i\n",argvv[i][0],errno);
                exit(0);
            }       
        }/*parent*/
        
        /*give job the name of the program*/        
        strcpy(job_name,argvv[i][0]);
        strcat(job_name," \n");
    
        addjob(jobs,pid,BG,job_name);         
        job=getjobpid(jobs,pid);
        printf("[%d] (%d) ", job->jid, job->pid);
        printf("%s", job->cmdline);
        
        /*in_pipe is now out_pipe    */
        dup2(out_pipe[0],in_pipe[0]);
        dup2(out_pipe[1],in_pipe[1]);     
        
        
        close(out_pipe[0]);
        close(out_pipe[1]);
        fflush(stdout); 
        
    
        
    }    
    close(in_pipe[1]);
    close(in_pipe[0]);
    /*since editting our job list has been done, we may start processing child signals*/
    Sigprocmask(SIG_UNBLOCK,&maskchld,NULL); 
        
    
    
    
    /*we can let default handlers reap, or we can do it manually.  
   * waitfg(pid); 
   * listjobs(jobs);    
   *  now we reap all the children. 
   *   for(i=0;i<num_forks;i++){
   *       waitpid(-1,NULL,0);
   *   }
  */
}

/*simple test for the fg_piped_create*/
void pipe_driver(){
    
    
    int num_forks = 3;
    char** argvv[3];
    argvv[0]=malloc(2*sizeof(char*));
    argvv[1]=malloc(3*sizeof(char*));
    argvv[2]=malloc(3*sizeof(char*));
    argvv[0][0]="/bin/ls";
    argvv[0][3]=0;
    
    argvv[1][0]="/bin/sort";
    argvv[1][1]="-r";
    argvv[1][2]=0;
    
    argvv[2][0]="/bin/grep";
    argvv[2][1]="txt";
    argvv[2][2]=0;
    fg_piped_create(argvv,num_forks);
}

/*simpler test for the fg_piped_create*/
void pipe_driver3(){
    int num_forks = 3;
    char** argvv[3];
    argvv[0]=malloc(2*sizeof(char*));
    argvv[1]=malloc(3*sizeof(char*));
    argvv[2]=malloc(3*sizeof(char*));
    argvv[0][0]="/bin/ls";
    argvv[0][3]=0;
    
    argvv[1][0]="/bin/grep";
    argvv[1][1]="txt";
    argvv[1][2]=0;
    
    argvv[2][0]="/bin/grep";
    argvv[2][1]="11";
    argvv[2][2]=0;
    fg_piped_create(argvv,num_forks);
}

/*simpler test for the fg_piped_create*/
void pipe_driver2(){
    
    
    int num_forks = 1;
    char** argvv[1];
    argvv[0]=malloc(4*sizeof(char*));
    argvv[0][0]="/bin/ls";
    argvv[0][1]="-l";
    argvv[0][2]="-r";
    argvv[0][3]=0;
    fg_piped_create(argvv,num_forks);
}


/*THIS MODE OF CREATION IS DEPRECATED!!!  IT ONLY CAN RUN ONE PROGRAM, IT DOESN
 *DO ANY PIPING WHATSOEVER!!!!
 */
void fg_create(char *argv[]){

	int pid=-1;
	char* job_name;
    /*redundant block, it is that important!!*/
    Sigprocmask(SIG_BLOCK,&maskchld,NULL);    
        
    pid=Fork();
            
    if(pid==0){/*child*/
        Setpgid(0,0);   /*make child has own process group so it can share signals*/
            
        Sigprocmask(SIG_UNBLOCK,&maskchld,NULL);    /*this is the child, it should have this signal unblocked */
        Signal(SIGTSTP,SIG_DFL);        /*default SIGINT handler*/
        Signal(SIGINT,SIG_DFL);         /*default SIGSTP handler*/
        if(execv(argv[0],argv)==-1){               
            printf("%s: Command not found\n",argv[0]);
            exit(0);
        }       
    }/*parent*/
        
    /*give job the name of the program*/
    job_name = strcat(argv[0],"\n");
    
    addjob(jobs,pid,FG,job_name);

    /*since editting our job list has been done, we may start processing child signals*/
    Sigprocmask(SIG_UNBLOCK,&maskchld,NULL); 
    
    /*all we do now is sleep until the child finishes*/
    waitfg(pid);
        
    return;
}

